/*
 * @Author: LVGRAPE
 * @LastEditors: LVGRAPE
 */
#include "drv_pin.h"
#include "drv_i2s.h"
#include "assembly.h"
#include "coder.h"
#include "mp3common.h"
#include "mp3dec.h"
#include "maths.h"
// #include "mpadecobjfixpt.h"
#include "player.h"
#include "statname.h"

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include "w25qxx.h"
#include "mp3dec.h"

#define DBG_TAG "mp3"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

// ALSA functions declaration
int alsa_device_open(unsigned int channels, unsigned int sample_rate, unsigned int format_bits);
int alsa_device_write(int16_t *pcm, size_t frames);
void alsa_device_close(void);

static HMP3Decoder hMP3Decoder;
static MP3FrameInfo mp3FrameInfo;
short pcm[MAX_NCHAN * MAX_NGRAN * MAX_NSAMP];
// short pcm_0[MAX_NCHAN * MAX_NGRAN * MAX_NSAMP/2];

#define MAX_BUFFER_SIZE 2048
#define MIN_BUFFER_SIZE 1024

uint8_t mp3_data[MAX_BUFFER_SIZE];

void flash_read(uint32_t addr, uint8_t *data, uint32_t size)
{
    for (uint32_t i = 0; i < size; i++)
    {
        data[i] = *(uint8_t *)(addr + i);
    }
}
int mp3(int argc, char **argv)
{
    int init = 0;

    hMP3Decoder = MP3InitDecoder();
    if (!hMP3Decoder)
    {
        rt_kprintf("Failed to allocate MP3 decoder\n");
        // free(data);
        return -1;
    }
    pin_mode(PA6, PIN_MODE_OUTPUT_OD);
    pin_write(PA6, 1);
    // 解码一帧
    uint8_t *data_ptr = mp3_data;

    uint32_t read_addr = FLASH_SPIM_START_ADDR;
    uint32_t read_total = 0;
    // uint8_t readbuff[256];
    uint32_t total_size = 0;
    bool getInfo = 0;
    uint16_t frameSize = 0;
    if (!getInfo)
    {
        flash_read(read_addr, mp3_data, 256);
        struct sbc_info *info = (struct sbc_info *)mp3_data;
        rt_kprintf("Info: \n");
        rt_kprintf("    head: %02X\n", info->head);
        rt_kprintf("    addr: %08X\n", info->addr);
        rt_kprintf("    size: %ld\n", info->size);
        rt_kprintf("    len: %02d\n", info->name_len);
        rt_kprintf("    name: %s\n", info->name);
        read_addr += 256;
        getInfo = 1;
        total_size = info->size;
        rt_thread_mdelay(1);
    }

    flash_read(read_addr, mp3_data, MAX_BUFFER_SIZE);
    int bufferLeft = MAX_BUFFER_SIZE;
    uint32_t percets = 0;
    uint32_t dt_ptr = 0;
    while (read_total < total_size)
    {

        if (bufferLeft < (MIN_BUFFER_SIZE))
        {
            memcpy(mp3_data, data_ptr, bufferLeft);
            read_addr += MIN_BUFFER_SIZE;
            flash_read(read_addr, mp3_data + bufferLeft, MIN_BUFFER_SIZE);
            read_total += MIN_BUFFER_SIZE;
            bufferLeft += MIN_BUFFER_SIZE;
            data_ptr = mp3_data;
        }

        /* find start of next MP3 frame - assume EOF if no sync found */
        int offset = MP3FindSyncWord(data_ptr, bufferLeft);
        if (offset < 0)
        {
            rt_kprintf("No sync word found\n");
            break;
            // goto error;
        }

        data_ptr += offset;
        bufferLeft -= offset;
        dt_ptr = (uint32_t)data_ptr;
        int err = MP3Decode(hMP3Decoder, &data_ptr, &bufferLeft, pcm, 0);
        dt_ptr = (uint32_t)data_ptr - dt_ptr;
        frameSize = (uint32_t)data_ptr - (uint32_t)mp3_data;
        // rt_kprintf("data_ptr:%08X.%d offset:%4d frame:%d%% Left:%4d total:%8d read_addr:%08X size:%d\n", (uint32_t)data_ptr, dt_ptr, offset, (int)(percets), bufferLeft, read_total, read_addr, frameSize);
        if (err)
        {
#if 1
            switch (err)
            {
            case ERR_MP3_INDATA_UNDERFLOW:
                rt_kprintf("MP3 decoder: INDATA_UNDERFLOW\n");
                break;
            case ERR_MP3_MAINDATA_UNDERFLOW:
                rt_kprintf("MP3 decoder: MAINDATA_UNDERFLOW\n");
                break;
            case ERR_MP3_FREE_BITRATE_SYNC:
                rt_kprintf("MP3 decoder: FREE_BITRATE_SYNC\n");
                break;
            case ERR_MP3_OUT_OF_MEMORY:
                rt_kprintf("MP3 decoder: OUT_OF_MEMORY\n");
                break;
            case ERR_MP3_NULL_POINTER:
                rt_kprintf("MP3 decoder: NULL_POINTER\n");
                break;
            case ERR_MP3_INVALID_FRAMEHEADER:
                rt_kprintf("MP3 decoder: INVALID_FRAMEHEADER\n");
                break;
            case ERR_MP3_INVALID_SIDEINFO:
                rt_kprintf("MP3 decoder: INVALID_SIDEINFO\n");
                break;
            case ERR_MP3_INVALID_SCALEFACT:
                rt_kprintf("MP3 decoder: INVALID_SCALEFACT\n");
                break;
            case ERR_MP3_INVALID_HUFFCODES:
                rt_kprintf("MP3 decoder: INVALID_HUFFCODES\n");
                break;
            case ERR_MP3_INVALID_DEQUANTIZE:
                rt_kprintf("MP3 decoder: INVALID_DEQUANTIZE\n");
                break;
            case ERR_MP3_INVALID_IMDCT:
                rt_kprintf("MP3 decoder: INVALID_IMDCT\n");
                break;
            case ERR_MP3_INVALID_SUBBAND:
                rt_kprintf("MP3 decoder: INVALID_SUBBAND\n");
                break;
            default:
                rt_kprintf("MP3 decoder: error %d\n", err);
                break;
            }
// return -1;
#endif
            data_ptr += 1;
            bufferLeft -= 1;
            continue;
        }
        else
        {
            MP3GetLastFrameInfo(hMP3Decoder, &mp3FrameInfo);
            // 打印 MP3 信息
            if (init == 0)
            {
                rt_kprintf(" \r\n Bitrate       %dKbps", mp3FrameInfo.bitrate / 1000);
                rt_kprintf(" \r\n Samprate      %dHz", mp3FrameInfo.samprate);
                rt_kprintf(" \r\n BitsPerSample %db", mp3FrameInfo.bitsPerSample);
                rt_kprintf(" \r\n nChans        %d", mp3FrameInfo.nChans);
                rt_kprintf(" \r\n Layer         %d", mp3FrameInfo.layer);
                rt_kprintf(" \r\n Version       %d", mp3FrameInfo.version);
                rt_kprintf(" \r\n OutputSamps   %d", mp3FrameInfo.outputSamps);
                rt_kprintf("\r\n");

                if (mp3FrameInfo.nChans == 0 || mp3FrameInfo.samprate == 0)
                {
                    rt_kprintf("Invalid MP3 format: channels=%d, sample_rate=%d\n", mp3FrameInfo.nChans, mp3FrameInfo.samprate);
                    continue;
                }
                init = 1;
            }

            if (mp3FrameInfo.outputSamps == 0)
            {
                rt_kprintf("Invalid MP3 format: outputSamps=%d\n", mp3FrameInfo.outputSamps);
                // return -1;
                continue;
                // goto error;
            }

            percets = (read_total + MAX_BUFFER_SIZE - bufferLeft) * 100 / total_size;

            int frames = mp3FrameInfo.outputSamps / mp3FrameInfo.nChans;
            rt_kprintf("percets: %d%% frames: %d/%d \n", percets, frames, mp3FrameInfo.outputSamps);
            // rt_kprintf("frames: %d/%d \n", frames, mp3FrameInfo.outputSamps);

            // for (int i = 0; i < frames; i++)
            // {
            //     pcm_0[i] = pcm[i * mp3FrameInfo.nChans]/2;
            // }
            // for(int i = 0; i < mp3FrameInfo.outputSamps; i++)
            // {
            //     pcm[i] = 0;
            // }
            // rt_memset(pcm, 0, sizeof(pcm));
            i2s_dma_tx(pcm, mp3FrameInfo.outputSamps);
        }

        // rt_kprintf("",read_addr,read_total,percets / 100, percets % 100,bufferLeft,r)
    }

    MP3FreeDecoder(hMP3Decoder);
    // free(data);
    // alsa_device_close();

    return 0;
}
int i2s_test(void)
{
    for (int j = 0; j < 1024; j++)
    {
        for (int i = 0; i < 1024; i++)
        {
            pcm[i] = i;
        }
        i2s_dma_tx(pcm, 1024);
    }
    return 0;
}
MSH_CMD_EXPORT(i2s_test, i2s_test);
MSH_CMD_EXPORT(mp3, mp3 play test);
